Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding a sample Firebolt plugin. #784

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

Karthick-Somasundaresan
Copy link
Contributor

No description provided.

@Karthick-Somasundaresan Karthick-Somasundaresan marked this pull request as draft March 6, 2024 07:57
@@ -0,0 +1,6 @@
startmode = "@PLUGIN_FIREBOLTPRIVACY_AUTOSTART@"
callsign = "Privacy"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this intentional? Typically we use the name of the file (FireboltPrivacy -> FireboltPrivacy.json) and than the callsign automatically becomes FireboltPrivacy. You are now overruling this name by setting the callsign. This is, like mentioned deviating from the standard.... If required, please make sure to document it her that it is required for backwards compatibility.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is intentional. The Firebolt APIs didn't have the prefix Firebolt (eg. Privacy.AllowResumePoints) . I have changed the callsign to Privacy to maintain the same method names. I felt having Privacy alone as the plugin name, doesn't add meaning hence kept the plugin name as FireboltPrivacy and callsign as Privacy.

_fireboltPrivacy = service->Root<Exchange::IFireboltPrivacy>(_connectionId, RPC::CommunicationTimeOut, _T("FireboltPrivacyImplementation"));
if (_fireboltPrivacy != nullptr) {
_fireboltPrivacy->Register(&_connectionNotification);
Exchange::JFireboltPrivacy::Register(*this, _fireboltPrivacy);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not do this as the final step? Only hookup the JSONRPC interface if all the other steps succeeded..

_service->Unregister(&_connectionNotification);

if (_fireboltPrivacy != nullptr) {
Exchange::JFireboltPrivacy::Unregister(*this);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure if you register the JSONRPC only if all succeeded, that you only Unregister it if all was succeeded..

#include <interfaces/IConfiguration.h>
#include <interfaces/IFireboltPrivacy.h>
#include <interfaces/IDictionary.h>
#include <interfaces/IStore.h>
Copy link
Contributor

@pwielders pwielders Mar 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IStore.h and IDictionary.h are different implemtations for the sme functionality. Suggest to focus on IDictionary than and not IStore. (so only include one of them, preferably IDictionary.h)

Going to the remainder of the code. I see you already use the IDictionary, which is good, so remove the reference to IStore.h.

Core::hresult Register(Exchange::IFireboltPrivacy::INotification* notification) override
{
ASSERT(notification != nullptr);
ASSERT(std::find(_notifications.begin(), _notifications.end(), notification) == _notifications.end());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move the assert within the Lock.

ASSERT(notification != nullptr);
ASSERT(std::find(_notifications.begin(), _notifications.end(), notification) == _notifications.end());
_adminLock.Lock();
notification->AddRef();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no need to put the AddRef within the lock.

ASSERT(std::find(_notifications.begin(), _notifications.end(), notification) == _notifications.end());
_adminLock.Lock();
notification->AddRef();
_notifications.push_back(notification);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a fool-proof example (people will copy-paste this :-) ) only add the Notification interface if it is not find. Still ASSERT on it, but in Release we will not add it and return an error code for it)

}
_adminLock.Unlock();

return Core::ERROR_NONE;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please report an error if you could not unregister it, also ASSERT on it if the notification could not be found.
We promote defensive coding these ASSERTS help in these defensive coding.

_adminLock.Unlock();
} else {
if (_localStore == nullptr) {
_localStore = _service->QueryInterfaceByCallsign<Exchange::IDictionary>("Dictionary");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not think that magicals in the code show proper coding ;-) Why not have 1 config value, specified as "Dictionary" default callsign for the Dictionary plugin. Than if you want to use in memory, in config, specify this "callsign": null that we want to take it out of memory. This way, if the dictionary plugin is called org.rdk.dictionary, you do not need to change a single line of code.

allowResumePoints = _allowResumePoints;
_adminLock.Unlock();
} else {
if (_localStore == nullptr) {
Copy link
Contributor

@pwielders pwielders Mar 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are several serious flaws here that must be resolved properly!

Use case scenario 1 (race condition):
First run, _localStore == nullptr, the Thread gets pre-empted after the if.
Another thread also executes this method. it will find _localStore == nullptr...
You do the math..

Use case scenario 2 (functional flaw):

  1. _localStore == nullptr, you grap the first time the IDictionary of the plugin..
  2. The dictionary plugin is deactivated.
  3. Again a call is made to this method... you do the math..

Solution: https://github.com/rdkcentral/Thunder/blob/master/Source/plugins/Types.h#L239C11-L239C30 us this class and all should be peachy..

}
if (_localStore != nullptr) {
string value;
_localStore->Get("FireboltPrivacy", "AllowResumePoints", value);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about a:
static TCHAR* constexp PrivacyNamespace[] = _T("FireboltPrivacy");
static TCHAR* constexp PrivacyKeyAllowResume[] = _T("AllowResumePoints");

Bottomline, magicals should be located in 1 place preferably in a header, so we can all use them and not all use a text literal.

if (_localStore != nullptr) {
string value;
_localStore->Get("FireboltPrivacy", "AllowResumePoints", value);
if (value.empty() || value == "false" ) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

False is not allowed ? Or FALSE ?

}
} else {
SYSLOG(Logging::Error,(_T("UNABLE TO GET DICTIONARY INTERFACE")) );
return Core::ERROR_RPC_CALL_FAILED;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See coding guidelines and I think it is even a rule, one return per method (Maintainability)

}
_adminLock.Unlock();
} else {
if (_localStore == nullptr) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issues as in the get :-)

_localStore->Set("FireboltPrivacy", "AllowResumePoints", "false");
}
_adminLock.Lock();
for(auto notification: _notifications){
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Design flaw:
This sounds as a bad idea... The JSONRPC is living in the WPEFramework process. In case we are running this out-of-process, it means that for each subscriber we need to pass the process boundary (expensive). Move the JSONRPC notification handling into the Plugin itself and report once the notification from here and the broadcast from the event from the WPEFramework process.

Given the usecase that one might be waiting on this information and than callback into this plugin, you have a deadlock. Suggest to decouple this notification in WPEFramework as there you also have a Workerpool AND you migh accumulate pending updates.

Config config;
config.FromString(service->ConfigLine());
_service = service;
Core::JSON::EnumType<Exchange::IFireboltPrivacy::StorageLocation> storageLocation = config.StorageLocation.Value();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As suggested, oly use a callsign to odentify a plugin that holds the IDictionary callsign, if null is set on this value assume in memory..

if (storageLocation == Exchange::IFireboltPrivacy::StorageLocation::InMemory) {
_inMemory = true;

_localStore = _service->QueryInterfaceByCallsign<Exchange::IDictionary>("Dictionary");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


private:
PluginHost::IShell* _service;
mutable Core::CriticalSection _adminLock;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mutable is only needed if you want to call non-const methods on a member object (like Core:CriticalSection) in a const method in this class. Right now you do not need it as there are no const methods in this class the require the access to the _adminLock. However after resolving all the review remarks, you do need it ;-)

#define MODULE_NAME Plugin_FireboltPrivacy
#endif

#include <core/core.h>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you include the core/core.h here as being a dependency also put it in the CMakeLists.txt (consistency)


#include <core/core.h>
#include <plugins/plugins.h>
#include <messaging/messaging.h>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See core (also applicable than to messaging :-)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure that the modules you include here, end up here: https://github.com/rdkcentral/Thunder/blob/master/Source/plugins/Types.h#L239C11-L239C30

target_link_libraries(${MODULE_NAME}
PRIVATE
CompileSettingsDebug::CompileSettingsDebug
${NAMESPACE}Plugins::${NAMESPACE}Plugins
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Finding the package required is step 1, inclusing them is step 2 :-) You should include Core and Messaging here as well.

@rdkcmf-jenkins
Copy link

Blackduck scan failure details

Summary: 0 violations, 0 files pending approval, 3 files pending identification.

  • Protex Server Path: /home/blackduck/github/ThunderNanoServices/784/rdkcentral/ThunderNanoServices

  • Commit: 8fd0cd5

Report detail: gist

@rdkcmf-jenkins
Copy link

WARNING: A Blackduck scan failure has been waived

A prior failure has been upvoted

  • Upvote reason: Approved existing but please see prior comment

  • Commit: 8fd0cd5

@rdkcmf-jenkins
Copy link

Blackduck scan failure details

Summary: 0 violations, 0 files pending approval, 3 files pending identification.

  • Protex Server Path: /home/blackduck/github/ThunderNanoServices/784/rdkcentral/ThunderNanoServices

  • Commit: 8fd0cd5

Report detail: gist

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants